package com.cloud.utils;

import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.StrUtil;
import com.cloud.sensitive.Sensitive;
import com.cloud.sensitive.SensitiveMode;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 数据脱敏工具类
 *
 * @author yzj
 */
public class SensitiveUtils<T> {

    // 实体对象
    public T object;

    // 脱敏数据列表
    private List<T> list;

    // 注解列表
    private List<Object[]> fields;

    /**
     * 初始化数据/列表
     */
    private void inList(List<T> list) {
        if (list == null) {
            list = new ArrayList<>();
        }
        this.list = list;
        setTouchyField();
    }

    /**
     * 初始化数据/对象
     */
    private void inBean(T vo) {
        list = new ArrayList<T>();
        if (vo != null) {
            list.add(vo);
        }
        setTouchyField();
    }

    /**
     * 设置敏感字段
     */
    private void setTouchyField() {
        this.fields = new ArrayList<Object[]>();
        List<Field> tempFields = new ArrayList<>();
        tempFields.addAll(Arrays.asList(object.getClass().getSuperclass().getDeclaredFields()));
        tempFields.addAll(Arrays.asList(object.getClass().getDeclaredFields()));
        for (Field field : tempFields) {
            if (field.isAnnotationPresent(Sensitive.class)) {
                putToField(field, field.getAnnotation(Sensitive.class));
            }
        }
    }

    private void putToField(Field field, Sensitive sensitive) {
        if (sensitive != null) {
            this.fields.add(new Object[]{field, sensitive});
        }
    }

    /**
     * 对类的属性进行脱敏
     *
     * @param vo 脱敏对象
     * @return
     */
    private void touchyField(T vo) {
        for (Object[] data : fields) {
            Field field = (Field) data[0];
            Sensitive sensitive = (Sensitive) data[1];
            // 设置实体类私有属性可访问
            field.setAccessible(true);
            if (vo != null || sensitive != null || field != null) {
                // 获取属性后现在默认处理的是String类型,其他类型数据可扩展
                try {
                    field.set(vo, touchyTactics(String.valueOf(field.get(vo)), sensitive.typeMode()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 脱敏策略
     *
     * @param str      字符串
     * @param typeMode 脱敏类型
     * @return
     */
    private String touchyTactics(String str, SensitiveMode typeMode) {
        if (StrUtil.isBlank(str)) {
            return StrUtil.EMPTY;
        }
        String newStr = str;
        switch (typeMode) {
            case CHINESE_NAME:
                newStr = DesensitizedUtil.chineseName(str);
                break;
            case ID_CARD:
                newStr = DesensitizedUtil.idCardNum(str, 1, 2);
                break;
            case FIXED_PHONE:
                newStr = DesensitizedUtil.fixedPhone(str);
                break;
            case MOBILE_PHONE:
                newStr = DesensitizedUtil.mobilePhone(str);
                break;
            case ADDRESS:
                newStr = DesensitizedUtil.address(str, 8);
                break;
            case EMAIL:
                newStr = DesensitizedUtil.email(str);
                break;
            case PASSWORD:
                newStr = DesensitizedUtil.password(str);
                break;
            case CAR_LICENSE:
                newStr = DesensitizedUtil.carLicense(str);
                break;
            case BANK_CARD:
                newStr = DesensitizedUtil.bankCard(str);
                break;
            default:
        }
        return newStr;
    }

    /**
     * 对List 数据对象进行脱敏处理
     */
    public void touchyList(List<T> list) {
        if (list != null && list.size() > 0) {
            // 初始化数据
            this.inList(list);
            int failTimes = 0;
            for (T vo : this.list) {
                // 遍历处理需要进行,脱敏的字段
                touchyField(vo);
            }
        }
    }

    /**
     * JavaBean 模式脱敏
     */
    public void touchyBean(T vo) {
        if (vo != null) {
            // 初始化数据
            this.inBean(vo);
            touchyField(vo);
        }
    }

}
